package com.powergisol.core.math;


public class Vector {

    private double x;

    private double y;

    private double z;

    private double module;


    public static Vector o = new Vector(0,0,0);

    /**
     * 已知两点A（x1，y1,z1），B（x2，y2,z1），则向量AB=（x2-x1，y2-y1,z2-z1）,B的坐标点减去A的坐标点
     * @param from
     * @param to
     */
    public Vector(Dot from, Dot to){
        this.x = to.getX() - from.getX();
        this.y = to.getY() - from.getY();
        this.z = to.getZ() - from.getZ();
        module();
    }

    public Vector(double x,double y,double z){
        this.x = x;
        this.y = y;
        this.z = z;
        module();
    }


    public Vector(){
        this(0,0,0);
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public double getZ() {
        return z;
    }

    /**
     * 求向量的模
     * @return
     */
    public double module() {
        double dis = Math.pow(this.x, 2) + Math.pow(this.y, 2) + Math.pow(this.z, 2);
        return module = Math.sqrt(dis);
    }

    /**
     * 与另一个向量的点积  如果大于0 是锐角 等于0 垂直，小于0 钝角
     * @param other
     * @return
     */
    public double  dotProduct(Vector other) {
        return this.getX() * other.getX() + this.getY()*other.getY() + this.getZ()*other.getZ();
    }

    /**
     * 求两个向量的角度
     * @param other
     * @return
     */
    public double getangle(Vector other) {
        if(other.equals(o)) {
            return 0;
        }
        else {
            double ans = this.dotProduct(other)/ (this.module * other.module);
            return Math.round(Math.acos(ans) * 180 / Math.PI);
        }
    }
    // TODO: 2020/9/16  应该判断另一个变量是否在同一条直线
    /**
     * 判断两个向量是否相等，
     * @param other
     * @return
     */
    public boolean equals(Vector other) {

        return this.getX()==other.getX() && this.getY()==other.getY() && this.getZ()==other.getZ();

    }

    /**
     * 判断两个向量是否平行
     * @param other
     * @param precision 保留几位小数
     * @return
     */
    public boolean parallalTo(Vector other,int precision) {
        // 0向量和所有向量平行
        if(other.equals(0)) {
            return true;
        }
        else {

            double x1 = this.getX(),y1 = this.getY(),z1 = this.getZ();
            double x2 = other.getX(),y2 = other.getY(),z2 = other.getZ();

            double a = compute(x1 * y2,precision);
            double b = compute(x2 * y1,precision);
            double c = compute(y1 * z2,precision);
            double d = compute(z1 * y2,precision);
            double e = compute(x1 * z2,precision);
            double f = compute(z1 * x2,precision);

            return a==b && c==d && e==f;
        }
    }

    /**
     * 对一个小数的多少位进行四舍五入
     * @param num
     * @param precision 保留小数多少位,必须大于0
     * @return
     */

    private double compute(double num, int precision){

        if(precision<0){
            throw new RuntimeException("精度必须为正整数!");
        }

        double pow = Math.pow(10, precision);
        return (double)Math.round(num*pow)/pow;

    }


    /**
     * 判断两个向量是否平行
     * @param other
     * @return
     */
    public boolean parallalTo(Vector other) {
        // 0向量和所有向量平行
        if(other.equals(0)) {
            return true;
        }
        else {
//            try {
//                if(other.getP().getX() / this.p.getX() ==other.getP().getY() / this.p.getY()) {
//                    return true;
//                }
//            }
//            catch (ArithmeticException e) {
//                if(this.x == v2.x && this.x == 0) return true;
//                else if(this.y == v2.y && this.y == 0) return true;
//            }
            double x1 = this.getX(),y1 = this.getY(),z1 = this.getZ();
            double x2 = other.getX(),y2 = other.getY(),z2 = other.getZ();
            /**
             * 这里为什么要三个条件 前面两个条件 当y1==y2==0时，也是成立的，但是此时并不能说明两个向量相等，第3个条件加入后，必须x y z 3个点的其中两个等于才满足平行
             * 符合结果逻辑
             */
            return (x1*y2 == y1*x2 && y1*z2 == z1*y2 && x1*z2 == z1*x2);
        }

    }

    /**
     * 返回两个向量的叉乘，返回的向量是这两个向量所在平面的法向量
     * a(x1,y1,z1), b(x2,y2,z2)  aXb = (y1z2-y2z1,-(x1z2-x2z1),x1y2-x2y1)
     * 公式推导 https://www.cnblogs.com/YouXiangLiThon/p/7997796.html
     * @param other
     * @return
     */
    public Vector crossProduct(Vector other){

        if(parallalTo(other)){
            throw new RuntimeException(this +"and "+other +"are parallel ");
        }

        double x1 = this.getX(),y1 = this.getY(),z1 = this.getZ();
        double x2 = other.getX(),y2 = other.getY(),z2 = other.getZ();

        double x = y1*z2-y2*z1;
        double y = -(x1*z2-x2*z1);
        double z = x1*y2-x2*y1;

        return new Vector(x,y,z);
    }

    /**
     * 判断是否垂直
     * @param other
     * @return
     */
    public boolean vertical(Vector other){

        double x1 = this.getX(),y1 = this.getY(),z1 = this.getZ();
        double x2 = other.getX(),y2 = other.getY(),z2 = other.getZ();
        return (x1*x2 + y1*y2 + z1*z2)==0;
    }

    @Override
    public String toString() {
        return "Vector{" +
                "x=" + x +
                ", y=" + y +
                ", z=" + z +
                ", module=" + module +
                '}';
    }


}
